/*
    绑定关系相关类的定义: 绑定关系类、绑定关系管理类
    1. 绑定关系类: 对交换机和消息队列的绑定关系的描述
        属性: 交换机名称、消息队列名称、路由规则、持久化标志
        方法: 创建绑定关系
    2. 绑定关系管理类: 对绑定关系数据的管理以及数据的持久化
        属性: 数据库文件(绑定数据持久化的目标数据库文件)、绑定关系数据映射表(<交换机名, <消息队列名, 绑定关系对象>>)
        方法: 声明绑定关系、解除绑定关系、解除指定交换机的所有绑定关系、解除指定队列的所有绑定关系、获取指定交换机的所有绑定关系
*/
#pragma once
#include "../common/helper.hpp"
#include "../common/logger.hpp"
#include <string>
#include <unordered_map>
#include <mutex>
#include <memory>
#include <sstream>
#include <vector>


namespace mq
{
    // 绑定关系类
    struct Binding
    {
        Binding() {}
        Binding(const std::string& exchanger_name, const std::string& msg_queue_name, const std::string& binding_key, bool durable):
            _exchanger_name(exchanger_name), _msg_queue_name(msg_queue_name), _binding_key(binding_key), _durable(durable)
        {}
        
        std::string _exchanger_name; // 交换机名称
        std::string _msg_queue_name; // 消息队列名称
        std::string _binding_key; // 路由规则
        bool _durable; // 持久化标志（取决于交换机和消息队列是否持久化）
        using BindingPtr = std::shared_ptr<Binding>;
    };

    // 绑定关系管理类
    class BindingManager
    { 
    public:
        using BindingManagerPtr = std::shared_ptr<BindingManager>;
        using MsgQueueBindingMap = std::unordered_map<std::string, Binding::BindingPtr>; // <消息队列名称, 绑定关系类>, 一对一的关系
        using BindingMap = std::unordered_map<std::string, MsgQueueBindingMap>; // <交换机名称, MsgQueueBindingMap>, 一对多的关系
    
    public:
        BindingManager(const std::string& db_file): _sqlite3_helper(db_file)
        {
            std::string parent_dir = FileHelper::parentDir(db_file);
            if(!FileHelper::createDir(parent_dir))
                ERR_LOG("create dir %s failed\n", parent_dir.c_str());
            if(!_sqlite3_helper.open())
                ERR_LOG("open binding db %s failed\n", db_file.c_str());
            createTable();
            _bindings = recoveryAllBindings();
        }

        // 声明绑定关系
        bool bind(const std::string& exchanger_name, const std::string& msg_queue_name, const std::string& binding_key, bool durable)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _bindings.find(exchanger_name);
            if(it != _bindings.end() && it->second.find(msg_queue_name) != it->second.end())
                return true;
            Binding::BindingPtr binding_ptr = std::make_shared<Binding>(exchanger_name, msg_queue_name, binding_key, durable);
            if(durable && !insertBinding(binding_ptr))
            {
                ERR_LOG("bind binding %s -> %s failed\n", exchanger_name.c_str(), msg_queue_name.c_str());
                return false;
            }
            _bindings[exchanger_name][msg_queue_name] = binding_ptr;
            return true;
        }

        // 解除绑定关系
        void unbind(const std::string& exchanger_name, const std::string& msg_queue_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it_binding = _bindings.find(exchanger_name);
            if(it_binding == _bindings.end()) 
                return;
            auto it_msg_queue_binding = it_binding->second.find(msg_queue_name);
            if(it_msg_queue_binding == it_binding->second.end())
                return;
            if(it_msg_queue_binding->second->_durable)
                deleteBinding(exchanger_name, msg_queue_name);
            it_binding->second.erase(it_msg_queue_binding);
        }

        // 删除指定交换机的所有绑定关系
        void removeExchangerBindings(const std::string& exchanger_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _bindings.find(exchanger_name);
            if(it == _bindings.end())
                return;
            deleteExchanagerBindings(exchanger_name);
            _bindings.erase(it);
        }
        
        // 删除指定消息队列的所有绑定关系
        void removeMsgQueueBindings(const std::string& msg_queue_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            deleteMsgQueueBindings(msg_queue_name);
            for(auto it_binding = _bindings.begin(); it_binding != _bindings.end(); ++it_binding)
            {
                auto it_msg_queue_binding = it_binding->second.find(msg_queue_name);
                if(it_msg_queue_binding != it_binding->second.end())
                    it_binding->second.erase(it_msg_queue_binding);
            }
        }

        // 获取指定交换机的所有绑定关系
        MsgQueueBindingMap getExchangerBindings(const std::string& exchanger_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _bindings.find(exchanger_name);
            if(it == _bindings.end())
                return {};
            return it->second;
        }

        /*
            下面测试相关的接口
        */
        // 获取指定绑定关系
        Binding::BindingPtr getBinding(const std::string& exchanger_name, const std::string& msg_queue_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it_binding = _bindings.find(exchanger_name);
            if(it_binding == _bindings.end())
                return nullptr;
            auto it_msg_queue_binding = it_binding->second.find(msg_queue_name);
            if(it_msg_queue_binding == it_binding->second.end())
                return nullptr;
            return it_msg_queue_binding->second;
        }

        // 判断指定绑定关系是否存在
        bool hasBinding(const std::string& exchanger_name, const std::string& msg_queue_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _bindings.find(exchanger_name);
            if(it == _bindings.end() || it->second.find(msg_queue_name) == it->second.end())
                return false;
            return true;
        }

        // 获取所有绑定关系个数
        size_t size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            size_t ret = 0;
            for(auto& e : _bindings)
            {
                ret += e.second.size();
            }
            return ret;
        }

        // 清空所有绑定关系
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            deleteTable();
            _bindings.clear();
        }

    private:
        /*
            绑定关系数据持久化相关操作
        */
        // 创建表
        void createTable()
        {
            #define BINDING_CREATE_TABLE_SQL "create table if not exists binding(exchanger_name varchar(32), msg_queue_name varchar(32), binding_key varchar(1024), durable int)"
            if(!_sqlite3_helper.execute(BINDING_CREATE_TABLE_SQL, nullptr, nullptr))
            {
                ERR_LOG("create table binding failed\n");
                abort();
            }
        }

        // 删除表
        void deleteTable()
       {
            #define BINDING_DELETE_TABLE_SQL "drop table if exists binding"
            if(!_sqlite3_helper.execute(BINDING_DELETE_TABLE_SQL, nullptr, nullptr))
            {
                ERR_LOG("drop table binding failed\n");
                abort();
            }
        }

        // 插入数据
        bool insertBinding(const Binding::BindingPtr& binding_ptr)
        {
            if(binding_ptr == nullptr)
            {
                DBG_LOG("insert binding failed, binding_ptr is nullptr\n");
                return false;
            }
            std::stringstream sql;
            sql << "insert into binding values(";
            sql << "'" << binding_ptr->_exchanger_name << "',";
            sql << "'" << binding_ptr->_msg_queue_name << "',";
            sql << "'" << binding_ptr->_binding_key << "',";
            sql << binding_ptr->_durable << ")";
            if (!_sqlite3_helper.execute(sql.str(), nullptr, nullptr))
            {
                ERR_LOG("insert binding failed\n");
                return false;
            }
            return true;
        }

        // 删除绑定关系
        void deleteBinding(const std::string& exchanger_name, const std::string& msg_queue_name)
        {
            std::stringstream sql;
            sql << "delete from binding where exchanger_name = '" << exchanger_name << "'";
            sql << "and msg_queue_name = '" << msg_queue_name << "'";
            if (!_sqlite3_helper.execute(sql.str(), nullptr, nullptr))
                ERR_LOG("failed to delete binding about %s -> %s\n", exchanger_name.c_str(), msg_queue_name.c_str());
        }

        // 删除指定交换机相关的绑定关系数据
        void deleteExchanagerBindings(const std::string& exchanger_name)
        {
            std::stringstream sql;
            sql << "delete from binding where exchanger_name = '" << exchanger_name << "'";
            if (!_sqlite3_helper.execute(sql.str(), nullptr, nullptr))
                ERR_LOG("failed to delete binding about %s\n", exchanger_name.c_str());
        }

        // 删除指定消息队列相关的绑定关系数据
        void deleteMsgQueueBindings(const std::string& msg_queue_name)
        {
            std::stringstream sql;
            sql << "delete from binding where msg_queue_name = '" << msg_queue_name << "'";
            if (!_sqlite3_helper.execute(sql.str(), nullptr, nullptr))
                ERR_LOG("failed delete binding about %s\n", msg_queue_name.c_str());
        }

        // 恢复绑定关系数据
        BindingMap recoveryAllBindings()
        {
            BindingMap binding_map;
            if(!_sqlite3_helper.execute("select * from binding;", selectCallback, &binding_map))
                ERR_LOG("get binding all failed\n");
            return binding_map;
        }

        // 回调函数
        static int selectCallback(void* arg, int col, char** values, char** files)
        {
            BindingMap* binding_map_ptr = reinterpret_cast<BindingMap*>(arg);
            Binding::BindingPtr binding_ptr = std::make_shared<Binding>(values[0], values[1], values[2], std::stoi(values[3]));
            auto& msg_queue_binding_map = (*binding_map_ptr)[binding_ptr->_exchanger_name];
            msg_queue_binding_map[binding_ptr->_msg_queue_name] = binding_ptr;
            return 0;
        }

    private:
        BindingMap _bindings;
        std::mutex _mutex;
        Sqlite3Helper _sqlite3_helper;
    };
}

